package bll

import (
	"go-micro.dev/v4/broker"
	"google.golang.org/protobuf/proto"
	"proto/dto"
	client "signal/client/broker"
	log "signal/collector/logger"
	"signal/event"
	"signal/lib/trace_log"
	"signal/model"
	"signal/utils"
)

var MQ = &mq{}

type mq struct {
}

func (m *mq) init() func() {
	// register event listener
	event.E.Register(event.DeviceStatusChange, m.eventHandle)
	event.E.Register(event.DeviceLocationReport, m.eventHandle)
	event.E.Register(event.DeviceBatteryReport, m.eventHandle)
	event.E.Register(event.DeviceSignalReport, m.eventHandle)
	event.E.Register(event.DeviceControlReport, m.eventHandle)
	event.E.Register(event.DeviceAlarm, m.eventHandle)
	event.E.Register(event.DeviceFault, m.eventHandle)
	event.E.Register(event.DeviceFaultCheck, m.eventHandle)
	event.E.Register(event.DeviceOTA, m.eventHandle)

	return func() {
		event.E.Unregister(event.DeviceStatusChange, m.eventHandle)
		event.E.Unregister(event.DeviceLocationReport, m.eventHandle)
		event.E.Unregister(event.DeviceBatteryReport, m.eventHandle)
		event.E.Unregister(event.DeviceSignalReport, m.eventHandle)
		event.E.Unregister(event.DeviceControlReport, m.eventHandle)
		event.E.Unregister(event.DeviceAlarm, m.eventHandle)
		event.E.Unregister(event.DeviceFault, m.eventHandle)
		event.E.Unregister(event.DeviceFaultCheck, m.eventHandle)
		event.E.Unregister(event.DeviceOTA, m.eventHandle)
	}
}

// received report data and publish it to RabbitMQ
func (m *mq) eventHandle(e event.Event, data interface{}) {
	var (
		err   error
		topic model.Topic
		body  []byte
	)

	sn := ""
	switch e {
	case event.DeviceStatusChange:
		topic = model.MQEventStatus

		d := data.(*dto.DeviceStatus)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceLocationReport:
		topic = model.MQEventLocation

		d := data.(*dto.Location)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceFault:
		topic = model.MQEventFault

		d := data.(*dto.Fault)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceAlarm:
		topic = model.MQEventAlarm

		d := data.(*dto.Alarm)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceBatteryReport:
		topic = model.MQEventBattery

		d := data.(*dto.BatteryInfo)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceSignalReport:
		topic = model.MQEventSignal

		d := data.(*dto.Signal)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceControlReport:
		topic = model.MQEventControl

		d := data.(*dto.Controller)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	case event.DeviceOTA:
		topic = model.MQEventOTA
		d := data.(*dto.OTAUpgradeNtf)
		if body, err = proto.Marshal(d); err != nil {
			log.Errorf("marshal data to proto error: %s", err)
			return
		}
		sn = d.Sn
	}

	if sn != "" {
		trace_log.DebugLogger(sn, string(topic), utils.ToJsonString(data))
	}

	if err = client.PubSub.Publish(string(topic), &broker.Message{Body: body}); err != nil {
		log.Errorf("publish data to rabbit error: %s", err)
		return
	}
}
